﻿namespace Xxtea
{
    using System;
    using System.Text;

    public sealed class XXTEA
    {
        private const uint delta = 0x9e3779b9;
        private static readonly UTF8Encoding utf8 = new UTF8Encoding();

        private XXTEA()
        {
        }

        public static byte[] Decrypt(byte[] data, byte[] key)
        {
            if (data.Length == 0)
            {
                return data;
            }
            return ToByteArray(Decrypt(ToUInt32Array(data, false), ToUInt32Array(FixKey(key), false)), true);
        }

        public static byte[] Decrypt(byte[] data, string key)
        {
            return Decrypt(data, utf8.GetBytes(key));
        }

        private static uint[] Decrypt(uint[] v, uint[] k)
        {
            int index = v.Length - 1;
            if (index >= 1)
            {
                uint y = v[0];
                int num7 = 6 + (0x34 / (index + 1));
                for (uint i = (uint) (num7 * 0x9e3779b9L); i != 0; i -= 0x9e3779b9)
                {
                    uint num2;
                    uint e = (i >> 2) & 3;
                    int num6 = index;
                    while (num6 > 0)
                    {
                        num2 = v[num6 - 1];
                        y = v[num6] -= MX(i, y, num2, num6, e, k);
                        num6--;
                    }
                    num2 = v[index];
                    y = v[0] -= MX(i, y, num2, num6, e, k);
                }
            }
            return v;
        }

        public static byte[] DecryptBase64String(string data, byte[] key)
        {
            return Decrypt(Convert.FromBase64String(data), key);
        }

        public static byte[] DecryptBase64String(string data, string key)
        {
            return Decrypt(Convert.FromBase64String(data), key);
        }

        public static string DecryptBase64StringToString(string data, byte[] key)
        {
            return utf8.GetString(DecryptBase64String(data, key));
        }

        public static string DecryptBase64StringToString(string data, string key)
        {
            return utf8.GetString(DecryptBase64String(data, key));
        }

        public static string DecryptToString(byte[] data, byte[] key)
        {
            return utf8.GetString(Decrypt(data, key));
        }

        public static string DecryptToString(byte[] data, string key)
        {
            return utf8.GetString(Decrypt(data, key));
        }

        public static byte[] Encrypt(byte[] data, byte[] key)
        {
            if (data.Length == 0)
            {
                return data;
            }
            return ToByteArray(Encrypt(ToUInt32Array(data, true), ToUInt32Array(FixKey(key), false)), false);
        }

        public static byte[] Encrypt(string data, byte[] key)
        {
            return Encrypt(utf8.GetBytes(data), key);
        }

        public static byte[] Encrypt(byte[] data, string key)
        {
            return Encrypt(data, utf8.GetBytes(key));
        }

        public static byte[] Encrypt(string data, string key)
        {
            return Encrypt(utf8.GetBytes(data), utf8.GetBytes(key));
        }

        private static uint[] Encrypt(uint[] v, uint[] k)
        {
            int index = v.Length - 1;
            if (index >= 1)
            {
                uint z = v[index];
                uint sum = 0;
                int num7 = 6 + (0x34 / (index + 1));
                while (0 < num7--)
                {
                    uint num3;
                    sum += 0x9e3779b9;
                    uint e = (sum >> 2) & 3;
                    int num6 = 0;
                    while (num6 < index)
                    {
                        num3 = v[num6 + 1];
                        z = v[num6] += MX(sum, num3, z, num6, e, k);
                        num6++;
                    }
                    num3 = v[0];
                    z = v[index] += MX(sum, num3, z, num6, e, k);
                }
            }
            return v;
        }

        public static string EncryptToBase64String(byte[] data, byte[] key)
        {
            return Convert.ToBase64String(Encrypt(data, key));
        }

        public static string EncryptToBase64String(string data, byte[] key)
        {
            return Convert.ToBase64String(Encrypt(data, key));
        }

        public static string EncryptToBase64String(byte[] data, string key)
        {
            return Convert.ToBase64String(Encrypt(data, key));
        }

        public static string EncryptToBase64String(string data, string key)
        {
            return Convert.ToBase64String(Encrypt(data, key));
        }

        private static byte[] FixKey(byte[] key)
        {
            if (key.Length == 0x10)
            {
                return key;
            }
            byte[] array = new byte[0x10];
            if (key.Length < 0x10)
            {
                key.CopyTo(array, 0);
                return array;
            }
            Array.Copy(key, 0, array, 0, 0x10);
            return array;
        }

        private static uint MX(uint sum, uint y, uint z, int p, uint e, uint[] k)
        {
            return ((((z >> 5) ^ (y << 2)) + ((y >> 3) ^ (z << 4))) ^ ((sum ^ y) + (k[(int) ((IntPtr) ((p & 3) ^ e))] ^ z)));
        }

        private static byte[] ToByteArray(uint[] data, bool includeLength)
        {
            int num = data.Length << 2;
            if (includeLength)
            {
                int num2 = (int) data[data.Length - 1];
                num -= 4;
                if ((num2 < (num - 3)) || (num2 > num))
                {
                    return null;
                }
                num = num2;
            }
            byte[] buffer = new byte[num];
            for (int i = 0; i < num; i++)
            {
                buffer[i] = (byte) (data[i >> 2] >> ((i & 3) << 3));
            }
            return buffer;
        }

        private static uint[] ToUInt32Array(byte[] data, bool includeLength)
        {
            uint[] numArray;
            int length = data.Length;
            int index = ((length & 3) != 0) ? ((length >> 2) + 1) : (length >> 2);
            if (includeLength)
            {
                numArray = new uint[index + 1];
                numArray[index] = (uint) length;
            }
            else
            {
                numArray = new uint[index];
            }
            for (int i = 0; i < length; i++)
            {
                numArray[i >> 2] |= (uint) (data[i] << ((i & 3) << 3));
            }
            return numArray;
        }
    }
}

